package com.atguigu.tingshu.album.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.RandomUtil;
import com.atguigu.tingshu.album.mapper.AlbumAttributeValueMapper;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.service.AlbumAttributeValueService;
import com.atguigu.tingshu.album.service.AlbumInfoService;
import com.atguigu.tingshu.album.service.AlbumStatService;
import com.atguigu.tingshu.album.service.AuditService;
import com.atguigu.tingshu.common.cache.GuiGuCache;
import com.atguigu.tingshu.common.config.redis.RedissonConfig;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.model.album.AlbumAttributeValue;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.AlbumStat;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.query.album.AlbumInfoQuery;
import com.atguigu.tingshu.user.client.UserFeignClient;
import com.atguigu.tingshu.vo.album.AlbumAttributeValueVo;
import com.atguigu.tingshu.vo.album.AlbumInfoVo;
import com.atguigu.tingshu.vo.album.AlbumListVo;
import com.atguigu.tingshu.vo.album.AlbumStatVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class AlbumInfoServiceImpl extends ServiceImpl<AlbumInfoMapper, AlbumInfo> implements AlbumInfoService {

    @Autowired
    private AlbumInfoMapper albumInfoMapper;
    @Autowired
    private AlbumAttributeValueMapper albumAttributeValueMapper;
    @Autowired
    private AlbumAttributeValueService albumAttributeValueService;
    @Autowired
    private AlbumStatService albumStatService;
    @Autowired
    private AlbumStatMapper albumStatMapper;
    @Autowired
    private TrackInfoMapper trackInfoMapper;
    @Autowired
    private AuditService auditService;
    @Autowired
    private RabbitService rabbitService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RedissonClient redissonClient;
    @Qualifier("com.atguigu.tingshu.user.client.UserFeignClient")
    @Autowired
    private UserFeignClient userFeignClient;

    /**
     * 保存专辑数据
     *
     * @param albumInfoVo
     * @param userId
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveAlbumInfo(AlbumInfoVo albumInfoVo, Long userId) {
        // 保存专辑数据,同时还需要保存专辑标签属性值到关联表,以及统计属性关联表

        //1.首先保存相应数据到专辑数据表
        AlbumInfo albumInfo = BeanUtil.copyProperties(albumInfoVo, AlbumInfo.class);
        albumInfo.setUserId(userId);
        albumInfo.setTracksForFree(5);
        albumInfo.setStatus(SystemConstant.ALBUM_STATUS_NO_PASS);

        albumInfoMapper.insert(albumInfo);


        //2.保存专辑标签属性值到关联表
        List<AlbumAttributeValue> attributeValueList = albumInfoVo.getAlbumAttributeValueVoList().stream().map(vo -> {
            AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
            albumAttributeValue.setAlbumId(albumInfo.getId());
            albumAttributeValue.setAttributeId(vo.getAttributeId());
            albumAttributeValue.setValueId(vo.getValueId());
            return albumAttributeValue;
        }).toList();

        albumAttributeValueService.saveBatch(attributeValueList);

        //3.统计属性关联表
        /*//3.保存专辑统计信息
        this.saveAlbumInfoStat(albumId, SystemConstant.ALBUM_STAT_PLAY, 0);
        this.saveAlbumInfoStat(albumId, SystemConstant.ALBUM_STAT_SUBSCRIBE, 0);
        this.saveAlbumInfoStat(albumId, SystemConstant.ALBUM_STAT_BUY, 0);
        this.saveAlbumInfoStat(albumId, SystemConstant.ALBUM_STAT_COMMENT, 0);
    }*/
        List<AlbumStat> albumStatList = new ArrayList<>();
        albumStatList.add(AlbumStat.builder().albumId(albumInfo.getId()).statType(SystemConstant.ALBUM_STAT_PLAY).statNum(0).build());
        albumStatList.add(AlbumStat.builder().albumId(albumInfo.getId()).statType(SystemConstant.ALBUM_STAT_SUBSCRIBE).statNum(0).build());
        albumStatList.add(AlbumStat.builder().albumId(albumInfo.getId()).statType(SystemConstant.ALBUM_STAT_BUY).statNum(0).build());
        this.saveAlbumInfoStat(albumStatList);

        //4.对专辑内容（标题、简介等）进行审核
        String auditText = albumInfo.getAlbumTitle() + albumInfo.getAlbumIntro();
        String suggestion = auditService.auditText(auditText);
        if ("pass".equals(suggestion)) {
            albumInfo.setStatus(SystemConstant.ALBUM_STATUS_PASS);
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_UPPER, albumInfo.getId());
        } else if ("block".equals(suggestion)) {
            albumInfo.setStatus(SystemConstant.ALBUM_STATUS_NO_PASS);
        } else if ("review".equals(suggestion)) {
            albumInfo.setStatus(SystemConstant.ALBUM_STATUS_ARTIFICIAL);
        }
        albumInfoMapper.updateById(albumInfo);

        /**
         * 保存专辑统计信息
         * @param albumId 专辑ID
         * @param statType 统计类型
         * @param statNum 统计数值 0401-播放量 0402-订阅量 0403-购买量 0403-评论数'
         * @param albumStatList
         */
    /*@Override
    public void saveAlbumInfoStat(Long albumId, String statType, int statNum) {
        AlbumStat albumStat = new AlbumStat();
        albumStat.setAlbumId(albumId);
        albumStat.setStatType(statType);
        albumStat.setStatNum(statNum);
        albumStatMapper.insert(albumStat);
    }*/
    }

    @Override
    public void saveAlbumInfoStat(List<AlbumStat> albumStatList) {
        albumStatService.saveBatch(albumStatList);
    }

    /**
     * 分页条件查询当前登录用户发布专辑
     *
     * @param pageInfo
     * @param albumInfoQuery
     * @return
     */
    @Override
    public IPage<AlbumListVo> findUserAlbumPage(IPage<AlbumListVo> pageInfo, AlbumInfoQuery albumInfoQuery) {
        return albumInfoMapper.findUserAlbumPage(pageInfo, albumInfoQuery);
    }

    /**
     * 根据专辑ID删除专辑
     *
     * @param id
     */
    @Override
    public void removeAlbumInfo(Long id) {
        //删除专辑以及对应的专辑标签关联表的 数据 和统计数据关联的数据
        //1.先判断专辑是否有对应声音有的话则不能删除
        Long count = trackInfoMapper.selectCount(new LambdaQueryWrapper<TrackInfo>().eq(TrackInfo::getAlbumId, id));
        if (count > 0) {
            throw new GuiguException(500, "该专辑有声音,请先删除声音再删除专辑");
        }
        //2.删除专辑数据
        albumInfoMapper.delete(new LambdaQueryWrapper<AlbumInfo>().eq(AlbumInfo::getId, id));
        //3.删除专辑标签关联表数据
        albumAttributeValueMapper.delete(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId, id));
        //4.删除专辑统计数据
        albumStatMapper.delete(new LambdaQueryWrapper<AlbumStat>().eq(AlbumStat::getAlbumId, id));

        //5.采用RabbitMQ可靠性消息将从ES索引库删除
        rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_LOWER, id);
    }

    /**
     * 根据专辑ID查询专辑信息（包括专辑标签列表）
     *
     * @param id
     * @return
     */
    /*@Override
    public AlbumInfo getAlbumInfo(Long id) {
        try {
            //1.优先从分布式缓存Redis中获取业务数据，命中缓存直接返回即可
            //1.2 构建缓存业务数据Key
            String dataKey = RedisConstant.ALBUM_INFO_PREFIX + id;
            //1.1先从redis缓存中获取数据信息
            AlbumInfo albumInfo = (AlbumInfo) redisTemplate.opsForValue().get(dataKey);

            if (albumInfo != null){
                return albumInfo;
            }

            //2.尝试获取分布式锁
            String lockKey = dataKey+RedisConstant.CACHE_LOCK_SUFFIX;
            //2.1 基于RedissonClient对象创建锁对象
            RLock lock = redissonClient.getLock(lockKey);
            boolean flag = lock.tryLock(RedisConstant.ALBUM_LOCK_WAIT_PX1, RedisConstant.ALBUM_LOCK_EXPIRE_PX2, TimeUnit.SECONDS);
            if (flag){
                try {
                    //3.如果获取锁成功，则查询数据库
                    albumInfo = this.getAlbumInfoDB(id);
                    //经数据库查询成功后，将数据保存到Redis缓存中
                    redisTemplate.opsForValue().set(dataKey,albumInfo,RedisConstant.ALBUM_TIMEOUT+ RandomUtil.randomInt(600),TimeUnit.SECONDS);
                    return albumInfo;
                } catch (Exception e) {
                    lock.unlock();
                }
            }else {
                //4.如果没有到获取锁 ,自旋
                TimeUnit.MILLISECONDS.sleep(30);
                this.getAlbumInfo( id);
            }
            return albumInfo;
        } catch (InterruptedException e) {
            //5.如果Redis服务可不用，兜底处理：直接查询数据库
            log.error("Redis服务不可用，请检查Redis服务是否正常！");
            return this.getAlbumInfoDB(id);
        }
    }*/


    /**
     * 根据专辑ID查询专辑信息（包括专辑标签列表）
     *
     * @param id
     * @return
     */
    @Override
    @GuiGuCache(prefix = RedisConstant.ALBUM_INFO_PREFIX)
    public AlbumInfo getAlbumInfoDB(Long id) {
        AlbumInfo albumInfo = albumInfoMapper.selectById(id);
        List<AlbumAttributeValue> attributeValueList = albumAttributeValueMapper.selectList(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId, id));
        albumInfo.setAlbumAttributeValueVoList(attributeValueList);
        return albumInfo;
    }


    /**
     * 修改专辑信息
     *
     * @param id
     */
    @Override
    public void updateAlbumInfo(Long id, AlbumInfoVo albumInfoVo) {
        //修改专辑表中的数据,预期关联的标签数据直接删除从新查即可
        AlbumInfo albumInfo = BeanUtil.copyProperties(albumInfoVo, AlbumInfo.class);
        albumInfo.setId(id);
        albumInfoMapper.updateById(albumInfo);

        //删除专辑标签关联表数据
        albumAttributeValueMapper.delete(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId, id));
        //保存专辑标签关联表数据
        List<AlbumAttributeValueVo> attributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
        if (CollectionUtil.isNotEmpty(attributeValueVoList)) {
            List<AlbumAttributeValue> albumAttributeValueList = albumInfoVo.getAlbumAttributeValueVoList().stream().map(vo -> {
                AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
                BeanUtil.copyProperties(vo, albumAttributeValue);
                albumAttributeValue.setAlbumId(id);
                return albumAttributeValue;
            }).toList();
            albumAttributeValueService.saveBatch(albumAttributeValueList);
        }
        //4.对专辑内容（标题、简介等）进行审核
        String auditText = albumInfo.getAlbumTitle() + albumInfo.getAlbumIntro();
        String suggestion = auditService.auditText(auditText);
        if ("pass".equals(suggestion)) {
            albumInfo.setStatus(SystemConstant.TRACK_STATUS_PASS);
            //3.采用RabbitMQ可靠性消息将过审专辑存入ES索引库
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_UPPER, id);
        } else if ("block".equals(suggestion)) {
            albumInfo.setStatus(SystemConstant.TRACK_STATUS_NO_PASS);
        } else if ("review".equals(suggestion)) {
            albumInfo.setStatus(SystemConstant.TRACK_STATUS_ARTIFICIAL);
        }
        albumInfoMapper.updateById(albumInfo);
    }

    /**
     * 查询当前用户所有专辑列表
     *
     * @return
     */
    @Override
    public List<AlbumInfo> findUserAllAlbumList(Long userId) {
        LambdaQueryWrapper<AlbumInfo> albumInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        //1.根据id查询下专辑信息
        albumInfoLambdaQueryWrapper.eq(AlbumInfo::getUserId, userId);
        //2.专辑状态为审核通过
        albumInfoLambdaQueryWrapper.eq(AlbumInfo::getStatus, SystemConstant.ALBUM_STATUS_PASS);
        //3.返回的是专辑id以及专辑的名称
        albumInfoLambdaQueryWrapper.select(AlbumInfo::getId, AlbumInfo::getAlbumTitle);
        //4.对专辑按照id降序进行排序
        albumInfoLambdaQueryWrapper.orderByDesc(AlbumInfo::getId);
        //4.限制返回记录数，造成前端卡顿 TODO 后期前端改为带分页下拉框
        albumInfoLambdaQueryWrapper.last("limit 200");
        List<AlbumInfo> albumInfoList = albumInfoMapper.selectList(albumInfoLambdaQueryWrapper);
        return albumInfoList;
    }


    /**
     * 根据专辑ID查询专辑统计信息
     *
     * @param albumId
     * @return
     */
    @Override
    @GuiGuCache(prefix = RedisConstant.ALBUM_INFO_PREFIX+"stat:")
    public AlbumStatVo getAlbumStatVo(Long albumId) {
        AlbumStatVo albumStatVo = albumInfoMapper.getAlbumStatVo(albumId);
        return albumStatVo;
    }


}
